package org.diy.traffic.twitter;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.TimeZone;
import java.util.logging.Level;

import org.diy.traffic.util.TLog;

import winterwell.jtwitter.Twitter;
import winterwell.jtwitter.TwitterException;
import winterwell.jtwitter.TwitterForbiddenException;
import winterwell.jtwitter.Twitter.Message;
import winterwell.jtwitter.Twitter.Status;
import winterwell.jtwitter.Twitter.User;

public class TrafficTwitter {
	
	private Date lastDirectMessageCheck = new Date(0);
	private Date lastReplyMessageCheck  = new Date(0);
	private Date lastAllMessageCheck    = new Date(0);
	
	private Twitter twit;
	
	public static final int MSG_TYPE_ALL = 0;
	public static final int MSG_TYPE_DIRECT = 1;
	public static final int MSG_TYPE_REPLY = 2;
	
	private long lastFollowerSynch = 0;
	
	public List<Status> chunkAndUpdateStatus(String long_status) throws TwitterException {
		
		List<Status> status_list = new ArrayList<Status>(0);
		
		List<String> chunked_updates = twit.splitMessage(long_status);
        return updateStatuses(chunked_updates);
	}
	
	
	public Status updateStatus(String status) throws TwitterException {
		return twit.updateStatus(status);
	}
	
	public List<Status> getUserTimeline() throws TwitterException {
		return twit.getUserTimeline();
	}
	
	
	public List<Status> updateStatuses( List<String> statuses) throws TwitterException {
		List<Status> status_list = new ArrayList<Status>();
				
		Iterator i = statuses.iterator();
		while (i.hasNext()) {
			String status_text = (String) i.next();
			Status s = this.updateStatus(status_text);
			status_list.add(s);
		}
		return status_list;
	}
	
	public TrafficTwitter(String username, String password) {
		twit = new Twitter(username, password);
	}	
	
	public List<String> splitMessage(String long_msg) {
		return twit.splitMessage(long_msg);
	}
	
	public Message sendMessage(String username, String message) throws TwitterException{
		return twit.sendMessage(username, message);
	}
	
	public List<Message> sendMessages(String username, List<String> messages) throws TwitterException {
		List<Message> message_list = new ArrayList<Message>();
		
		Iterator i = messages.iterator();
		while (i.hasNext()) {
			String message_text = (String) i.next();
			System.out.println("forwarding a message " + message_text + " to " + username );
			Message m = this.sendMessage(username, message_text);
			message_list.add(m);
		}
		return message_list;
	}
	
	public List<Message> forwardStatuses(String username, List<Status> statuses) throws TwitterException {
		

		List<String> message_txt_list = new ArrayList<String>();
		
		Iterator i = statuses.iterator();
		while (i.hasNext()) {
			Status next_status = (Status) i.next();
			String message_text = next_status.getText();
			message_txt_list.add(message_text);
		}
		return this.sendMessages(username, message_txt_list);
	}
	
	/**
	 * A function which does a search on recent statuses posted by me and filters the ones that have 
	 * occurred within a given number of seconds.
	 * 
	 * The call to twit.searchMyStatuses retrieves a list of statuses posted by me in the previous 24 hours,
	 * and this function filters that list down to ones that have occurred within the past given number of
	 * seconds.
	 *  
	 * @param query A string for which to search status messages posted by the authenticating user (within the last 24 hrs)
	 * @param seconds A value representing how within many seconds back search results should be included.
	 * @return A list of Statuses that have been posted by the authenticating user in the past 'seconds' seconds.
	 * @throws TwitterException If something goes wrong with executing the search on Twitter.
	 */
	public List<Status> searchMyRecentStatuses(String query, int seconds) throws TwitterException {
		
		// Perform the search on Twitter. The 'searchMyStatuses' function is hardcoded to only find
		// statuses from the past 24hrs.
		// TODO that should probably be changed, or broken out to another function
		List<Status> recent_statuses = twit.searchMyStatuses(query);
		TLog.log(Level.FINEST, String.format("Found %s recent status updates which match query '%s'", 
				recent_statuses.size(), query));
		
		// convert seconds to hours
		int number_of_hours = seconds / 60 / 60;
		
		/**
		 * This whole calendar stuff confuses the heck out of me!
		 * For some reason, we don't need to do any time-zone accounting here, because
		 * the created_at date from the Twitter status is automagically converted in Java to be relative to our
		 * time zone. Sweet!
		 * 
		 * I had a lot of confusing code in here to convert between calendar dates (no longer needed) and got 
		 * confused about this:
		 * Apparently 
		 *     Calendar.getInstance("GMT+00:00").getTime()
		 * will automatically do a conversion to give the time relative to your current location, while
		 *      Calendar.getInstance("GMT+00:00").get(Calendar.HOUR_OF_DAY)
		 * will give you the actual hour of the day a british guy would see right now when he looks at his clock
		 * (i.e. doesn't do the conversion).
		 * 
		 * Just FYI :)
		 */
		
		Calendar calendar_now = GregorianCalendar.getInstance(TimeZone.getDefault());
		calendar_now.setTimeInMillis(System.currentTimeMillis());
		
		//System.out.println("Pre-Roll: " + calendar_now.getTime());
		
		// subtract the calculated number of hours from the calendar 
		calendar_now.add(Calendar.HOUR_OF_DAY, -number_of_hours);
		
		//System.out.println("Post-Roll: " + calendar_now.getTime());
		Date some_time_ago = calendar_now.getTime();

		ArrayList<Status> filtered_statuses = new ArrayList<Status>();
		Iterator<Status> statusI = recent_statuses.iterator();		
	
		// iterate through the list of statuses returned, getting only the ones which are within the time limit
		while (statusI.hasNext()) {
			Status next_status = statusI.next();
			
			// get the date this one was created
			Date created_at = next_status.getCreatedAt();
			
			TLog.log(Level.FINEST, String.format("Comparing message '%s' creation time (%s) to cutoff (%s)", 
					next_status.text, created_at, some_time_ago));
			
			if (created_at.compareTo(some_time_ago) > 0) {
				//System.out.println("***MORE RECENT***");
				filtered_statuses.add(next_status);
			} else {
				//System.out.println("***NOT MORE RECENT***");
			}
		}
		
		TLog.log(Level.FINEST, String.format("Found only %s status updates matching query '%s' within %s hours", 
				filtered_statuses.size(), query, number_of_hours));
		return filtered_statuses;
	}
	
	public List<User> extractUserList(List<Message> message_list) {
		List<User> user_list = new ArrayList<User>(0);
		ListIterator l = message_list.listIterator();
		
		//figure out which users the messages should go to..
		while (l.hasNext()) {
			Message m = (Message) l.next();
			//System.out.println("in here, message is '" + m.getText() + "'");
			User sender = m.getSender();
			System.out.println("Message " + m.getId() + " sent by " + sender.screenName);
			if (!user_list.contains(sender)) {
				user_list.add(sender);
			}
		}
		
		return user_list;
	}
	
	public void sendMessageToGroup(List<String> message_list, List<User> user_list) throws TwitterException {
		ListIterator user_iterator = user_list.listIterator();
		
		
		while (user_iterator.hasNext()) {
			User u = (User) user_iterator.next();
			
			ListIterator message_iterator = message_list.listIterator();
			while (message_iterator.hasNext()) {
				System.out.println("Sending a message to " + u.screenName);
				String message = (String)message_iterator.next();
				System.out.println("The message I'm sending is " + message);
			
				
				System.out.println("message length (" + message.length() + ")");
				if (message.length() > 140) {
					message = message.substring(0, 140);
				}
				twit.sendMessage(u.screenName, message);
				try { Thread.sleep(500); }
				catch (InterruptedException ie) {System.out.println("TrafficTwitter can't sleep!");}
			}
		}
	}
	
	/*
	public List<Message> checkForMsgSinceLastCheck(boolean do_update, int msg_type) throws TwitterException {
		List<Message> l = null;
		
		switch(msg_type) {
			case MSG_TYPE_DIRECT:
				l = checkForMsgSince(lastDirectMessageCheck, msg_type);
				if (do_update) lastDirectMessageCheck.setTime(System.currentTimeMillis());
				break;
			case MSG_TYPE_REPLY:
				l = checkForMsgSince(lastReplyMessageCheck, msg_type);
				if (do_update) lastReplyMessageCheck.setTime(System.currentTimeMillis());
				break;
			case MSG_TYPE_ALL:
				l = checkForMsgSince(lastAllMessageCheck, msg_type);
				if (do_update) lastAllMessageCheck.setTime(System.currentTimeMillis());
				break;
		}	
				
		return l;
	}
	*/
		
	
	
	/** This function checks the Twitter account for direct messages since a particular message id
	 * TODO refactor and combine this function with "checkForMsgSince" ==> this is really sloppy!
	 * **/
	public List<Message> checkForMsgSinceId(long since_id, int msg_type) throws TwitterException {
		
		List<Message> message_list = new ArrayList<Message>(0);
		message_list = twit.getDirectMessagesSinceId(since_id);
		 
		// do some filtering here, based on msg_type parameter
		ListIterator l = message_list.listIterator();
		while (l.hasNext()) {
			Message m = (Message) l.next();
			
			if (m.isPublic() == true) { //it's an @reply
				if (msg_type == MSG_TYPE_DIRECT) message_list.remove(m);
			} else { // it's a direct message
				if (msg_type == MSG_TYPE_REPLY) message_list.remove(m);
			}
		}
		
		return message_list;
	}
	
	
	
	/** This function checks the Twitter account for direct messages which need to be handled **/
	public List<Message> checkForMsgSince(long since_date, int msg_type) throws TwitterException {
		
		List<Message> message_list = new ArrayList<Message>(0);
		
		//System.out.println("Getting DMs since " + new Date(since_date));
		message_list = twit.getDirectMessages(new Date(since_date));
		 
		// do some filtering here, based on msg_type parameter
		ListIterator l = message_list.listIterator();
		while (l.hasNext()) {
			Message m = (Message) l.next();
			
			if (m.isPublic() == true) { //it's an @reply
				if (msg_type == MSG_TYPE_DIRECT) message_list.remove(m);
			} else { // it's a direct message
				if (msg_type == MSG_TYPE_REPLY) message_list.remove(m);
			}
		}
		
		//System.out.println("Found " + message_list.size() + " messages");
		return message_list;
	}
	
	public long getLastFollowerSynch() {
		return this.lastFollowerSynch;
	}
	
	public void followFollowers() throws TwitterException{
		ArrayList<User> i_follow_list = (ArrayList) twit.getFriends();
		ListIterator i = i_follow_list.listIterator();
		TLog.log(Level.FINEST, "People I follow:");
		while (i.hasNext()) {
			TLog.log(Level.FINEST,
					((User) i.next()).screenName
					);
		}
		
		ArrayList<User> follows_me_list = (ArrayList) twit.getFollowers();
		ListIterator j = follows_me_list.listIterator();
		TLog.log(Level.FINEST, "People who follow me:");
		while (j.hasNext()) {
			User u = (User) j.next();
			TLog.log(Level.FINEST, u.screenName);
			if ( (Twitter.getUser(u.screenName, i_follow_list)) == null) {
				TLog.log(Level.INFO, "Attempting to follow " + u.screenName);
				try {
					twit.befriend(u.screenName);
				} catch (TwitterForbiddenException tfe) {
					TLog.log(Level.WARNING, String.format("Error (%s) trying to follow user '%s'; possibly protected? Continuing...", tfe.getMessage(), u.screenName));
				}
			}
		}
		
		this.lastFollowerSynch = System.currentTimeMillis();
	}
}
